//
// Ruler.java
//
package com.photoexpert;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Toolkit;
import javax.swing.JComponent;

class Ruler extends JComponent {

    enum DIRECTIONS {
        HORIZONTAL,
        VERTICAL
    }
    enum UNIT_MODES {
        DOT,
        CENTIMETER,
        INCH
    }

    static Ruler getHRuler() {
        if(_hRuler == null)
            _hRuler = new Ruler(DIRECTIONS.HORIZONTAL);
        return _hRuler;
    }
    static Ruler getVRuler() {
        if(_vRuler == null)
            _vRuler = new Ruler(DIRECTIONS.VERTICAL);
        return _vRuler;
    }
    static void setUnit(Ruler.UNIT_MODES unit) {
        _mode = unit;
        setIncrementAndUnits();
        if(_hRuler != null)
            _hRuler.repaint();
        if(_vRuler != null)
            _vRuler.repaint();
    }

    private static Ruler _hRuler = null;
    private static Ruler _vRuler = null;
    private static UNIT_MODES _mode = UNIT_MODES.DOT;
    private static int _increment;
    private static double _unit;
    private static final int ONE_INCH = Toolkit.getDefaultToolkit().getScreenResolution();
    private static final int SIZE = 22;

    private DIRECTIONS _direction;

    private Ruler(DIRECTIONS direction) {
        _direction = direction;
        setIncrementAndUnits();
    }

    private static void setIncrementAndUnits() {
        switch(_mode) {
            case DOT:
                _unit = 1;
                _increment = 50;
                break;
            case CENTIMETER:
                _unit = ((double)ONE_INCH / (double)2.54); // dots per centimeter
                _increment = 1;
                break;
            case INCH:
                _unit = ONE_INCH;
                _increment = 1;
                break;
        }
    }

    int getIncrement() {
        return (int)(_increment * _unit);
    }

    void setPreferredHeight(int ph) {
        setPreferredSize(new Dimension(SIZE, ph));
        revalidate();
    }

    void setPreferredWidth(int pw) {
        setPreferredSize(new Dimension(pw, SIZE));
        revalidate();
    }

    @Override
    public void paint(Graphics g)
    {
        Rectangle drawHere = g.getClipBounds();

        // Fill clipping area with dirty brown/orange.
        g.setColor(Presentor.Instance().getBackground());
        g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height);

        // Do the ruler labels in a small font that's black.
        g.setFont(new Font("SansSerif", Font.PLAIN, 9));
        g.setColor(Color.black);

        double start = 0;
        int startMark = 0;
        int endMark = 0;
        int tickLength = 10;
        String text = null;

        // ticks and labels
        double zoomRate = Presentor.Instance().getZoomRate();
        double unit = _unit * zoomRate;
        int increment = _increment;
        while(increment * unit < ONE_INCH / 2)
            increment *= 2;
        while(increment * unit > ONE_INCH)
            increment /= 2;

        // Use clipping bounds to calculate first and last tick locations.
        if(_direction == DIRECTIONS.HORIZONTAL)
        {
            startMark = (int)(drawHere.x / unit / increment);
            start = startMark * unit * increment;
            endMark = (int)((drawHere.x + drawHere.width) / unit / increment) + 1;
        }
        else
        {
            startMark = (int)(drawHere.y / unit / increment);
            start = startMark * unit * increment;
            endMark = (int)((drawHere.y + drawHere.height) / unit / increment) + 1;
        }

        // Make a special case of 0 to display the number
        // within the rule and draw a units label.
        String unit_txt = _mode == UNIT_MODES.DOT ? " dot" : _mode == UNIT_MODES.CENTIMETER ? " cm" : " in";
        if (start == 0)
        {
            if (_direction == DIRECTIONS.HORIZONTAL)
            {
                g.drawLine(0, SIZE - 1, 0, SIZE - tickLength - 1);
                g.drawString("0 " + unit_txt, 2, 8);
            }
            else
            {
                g.drawLine(SIZE - 1, 0, SIZE - tickLength - 1, 0);
                g.drawString("0", 3, 10);
                g.drawString(unit_txt, 3, 20);
            }
            startMark = 1;
            start = (int)(unit * increment);
        }

        int mark = startMark;
        double point = start;
        while(mark < endMark)
        {
            text = Integer.toString((int)(mark * increment)); // / zoomRate
            int intPoint = (int)point;

            if (_direction == DIRECTIONS.HORIZONTAL)
            {
                g.drawLine(intPoint, SIZE - 1, intPoint, SIZE - tickLength - 1);
                g.drawString(text, intPoint - 3, 8);
                if(_mode == UNIT_MODES.INCH)
                {
                    intPoint = (int)(point - unit * increment / 2);
                    g.drawLine(intPoint, SIZE - 1, intPoint, SIZE - tickLength / 2 - 1);
                }
            }
            else
            {
                g.drawLine(SIZE - 1, intPoint, SIZE - tickLength - 1, intPoint);
                g.drawString(text, 3, intPoint - 3);
                if(_mode == UNIT_MODES.INCH)
                {
                    intPoint = (int)(point - unit * increment / 2);
                    g.drawLine(SIZE - 1, intPoint, SIZE - tickLength / 2 - 1, intPoint);
                }
            }

            mark++;
            point += unit * increment;
        }
    }
}
